----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    00:40:38 12/04/2014 
-- Design Name: 
-- Module Name:    cpu - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity arithtest is
    Port ( clk : in  STD_LOGIC;
			  rst : in  STD_LOGIC;
           ram1_we : out  STD_LOGIC;
			  ram1_en : out  STD_LOGIC;
           ram1_oe : out  STD_LOGIC;
           ram1_addr : out  STD_LOGIC_VECTOR (17 downto 0);
           ram1_data : inout  STD_LOGIC_VECTOR (15 downto 0);
			  data_ready : in STD_LOGIC;
			  rdn: INOUT STD_LOGIC;
		     wrn: INOUT STD_LOGIC;
			  tsre : in STD_LOGIC;
			  tbre : in STD_LOGIC;
			  --ram2_we : out  STD_LOGIC;
			  --ram2_en : out  STD_LOGIC;
           --ram2_oe : out  STD_LOGIC;
           --ram2_addr : out  STD_LOGIC_VECTOR (17 downto 0);
           --ram2_data : inout  STD_LOGIC_VECTOR (15 downto 0);
			  instruction_test : in STD_LOGIC_VECTOR(15 downto 0);
			  output_test: out STD_LOGIC_VECTOR(15 downto 0));
end arithtest;

architecture Behavioral of arithtest is
signal clk_2 : STD_LOGIC := '0';
signal clk_4 : STD_LOGIC := '0';
signal clk_8 : STD_LOGIC := '0';

component IF_ram2 
	port(
		CLK, RST: IN STD_LOGIC;
--		使能端，判断该pc能否使用
		EN: IN STD_LOGIC;
--		程序计数器program counter
		pc: IN STD_LOGIC_VECTOR(15 DOWNTO 0);
--		从ram2中相应地址读出指令数据
		Ram2Addr: OUT STD_LOGIC_VECTOR(17 DOWNTO 0);
		Ram2Data: INOUT STD_LOGIC_VECTOR(15 DOWNTO 0);
--		根据pc地址输出相应指令
		instruction: OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
		Ram2OE, Ram2WE, Ram2EN: OUT STD_LOGIC
	);
end component;

component decoder
	port(   instruction : in  STD_LOGIC_VECTOR (15 downto 0);
           rs1 : out  STD_LOGIC_VECTOR (3 downto 0);
           rs2 : out  STD_LOGIC_VECTOR (3 downto 0);
           rd : out  STD_LOGIC_VECTOR (3 downto 0);
           imm : out  STD_LOGIC_VECTOR (10 downto 0);
           immCode : out  STD_LOGIC_VECTOR (2 downto 0);
           aluCode : out  STD_LOGIC_VECTOR (3 downto 0);
           rm : out  STD_LOGIC;
           wm : out  STD_LOGIC;
           wb : out  STD_LOGIC;
           pc_en : out  STD_LOGIC;
			  imm_en : out  STD_LOGIC
			  --;branch_en : out  STD_LOGIC
			  );
end component;

component pc_module
	Port ( current_pc : out  STD_LOGIC_VECTOR (15 downto 0);
           branch_pc : in  STD_LOGIC_VECTOR (15 downto 0);
           branch_en : in  STD_LOGIC;
			  clk: in STD_LOGIC);
end component;

component registers
	 Port ( --en : in  STD_LOGIC;
			  clk : in STD_LOGIC;
           rs1 : in  STD_LOGIC_VECTOR (3 downto 0);
           rs2 : in  STD_LOGIC_VECTOR (3 downto 0);
           rd : in  STD_LOGIC_VECTOR (3 downto 0);
           datain : in  STD_LOGIC_VECTOR (15 downto 0);
           dataOut_1 : out  STD_LOGIC_VECTOR (15 downto 0);
           dataOut_2 : out  STD_LOGIC_VECTOR (15 downto 0));
end component;

component branch_decision
    Port ( newpc_alu : in  STD_LOGIC_VECTOR (15 downto 0);
           cond_data2 : in  STD_LOGIC_VECTOR (15 downto 0);
           instruction : in  STD_LOGIC_VECTOR (15 downto 0);
           branch_en : out  STD_LOGIC;
			  --branch_en_in : in  STD_LOGIC;
           branch_pc : out  STD_LOGIC_VECTOR(15 downto 0));
end component;

component extender
    Port ( imm : in  STD_LOGIC_VECTOR (10 downto 0);
           immCode : in  STD_LOGIC_VECTOR (2 downto 0);
           extension : out  STD_LOGIC_VECTOR (15 downto 0));
end component;

component IF_ID
    Port ( pc_in : in  STD_LOGIC_VECTOR (15 downto 0);
           instruction_in : in  STD_LOGIC_VECTOR (15 downto 0);
           clk : in  STD_LOGIC;
           instruction_out : out  STD_LOGIC_VECTOR (15 downto 0);
           pc_out : out  STD_LOGIC_VECTOR (15 downto 0));
end component;



component id_ex
	port(
		clk:in std_logic;
		wb_in,wm_in:in std_logic;
		alu_in:in std_logic_vector(3 downto 0);
		data1_in,data2_in,imm_in:in std_logic_vector(15 downto 0);
		rd_in,rs1_in,rs2_in:in std_logic_vector(3 downto 0);
		rm_in,pcen_in,immen_in:in std_logic;
		nextpc_in:in std_logic_vector(15 downto 0);
		instruction_in:in std_logic_vector(15 downto 0);
		wb_out,wm_out:out std_logic;
		alu_out:out std_logic_vector(3 downto 0);
		data1_out,data2_out,imm_out:out std_logic_vector(15 downto 0);
		rd_out,rs1_out,rs2_out:out std_logic_vector(3 downto 0);
		rm_out,pcen_out,immen_out:out std_logic;
		nextpc_out:out std_logic_vector(15 downto 0);
		instruction_out:out std_logic_vector(15 downto 0)
	);
end component;

component alu 
	port(alucode:in std_logic_vector(3 downto 0);
		a,b:in std_logic_vector(15 downto 0);
		sign,zero,over,co:out std_logic;
		y:out std_logic_vector(15 downto 0)
		);
end component;

component ex_mem
	port(
		clk:in std_logic;
		wb_in,wm_in,rm_in:in std_logic;
		rd_in:in std_logic_vector(3 downto 0);
		result_in,data2_in:in std_logic_vector(15 downto 0);
		wb_out,wm_out,rm_out:out std_logic;
		rd_out:out std_logic_vector(3 downto 0);
		result_out,data2_out:out std_logic_vector(15 downto 0)
	);
end component;

component MEM_ram1
	port(
		CLK, RST: IN STD_LOGIC;
		rm, wm: IN STD_LOGIC;
		addr: IN STD_LOGIC_VECTOR(15 DOWNTO 0);
--		data端口在MEM中既当data_in又当data_out
		data_in: IN STD_LOGIC_VECTOR(15 DOWNTO 0);
		data_out: OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
--		addr_ram和data_ram
		Ram1Addr: OUT STD_LOGIC_VECTOR(17 DOWNTO 0);
		Ram1Data: INOUT STD_LOGIC_VECTOR(15 DOWNTO 0);
--		与串口访问相关的端口
		data_ready: IN STD_LOGIC;
		rdn: INOUT STD_LOGIC;
		wrn: INOUT STD_LOGIC;
		tbre: IN STD_LOGIC;
		tsre: IN STD_LOGIC;
--		ram1_en就是结构图中的ram_ce;
		ram1_en, ram1_oe, ram1_we: OUT STD_LOGIC
	);

end component;

component MEM_WB
    Port ( wb_in : in  STD_LOGIC;
           rd_in : in  STD_LOGIC_VECTOR (3 downto 0);
           data_in : in  STD_LOGIC_VECTOR (15 downto 0);
           clk : in  STD_LOGIC;
           data_out : out  STD_LOGIC_VECTOR (15 downto 0);
           wb_out : out  STD_LOGIC;
           rd_out : out  STD_LOGIC_VECTOR (3 downto 0));
end component;



signal bra_pc : STD_LOGIC_VECTOR(15 downto 0);
signal bra_en : STD_LOGIC;

signal pc_if : STD_LOGIC_VECTOR(15 downto 0);
signal instruction_if : STD_LOGIC_VECTOR (15 downto 0);
signal en_if : STD_LOGIC;

signal instruction_id : STD_LOGIC_VECTOR (15 downto 0);
signal rs1_id : STD_LOGIC_VECTOR (3 downto 0);
signal rs2_id : STD_LOGIC_VECTOR (3 downto 0);
signal rd_id : STD_LOGIC_VECTOR (3 downto 0);
signal imm_id : STD_LOGIC_VECTOR (10 downto 0);
signal immCode_id : STD_LOGIC_VECTOR (2 downto 0);
signal aluCode_id : STD_LOGIC_VECTOR (3 downto 0);
signal rm_id : STD_LOGIC;
signal wm_id : STD_LOGIC;
signal wb_id : STD_LOGIC;
signal pc_en_id : STD_LOGIC;
signal imm_en_id : STD_LOGIC;
signal pc_id : STD_LOGIC_VECTOR(15 downto 0);
signal dataOut_1_id : STD_LOGIC_VECTOR(15 downto 0);
signal dataOut_2_id : STD_LOGIC_VECTOR(15 downto 0);
signal immExt_id : STD_LOGIC_VECTOR(15 downto 0);

signal instruction_ex : STD_LOGIC_VECTOR (15 downto 0);
signal rs1_ex : STD_LOGIC_VECTOR (3 downto 0);
signal rs2_ex : STD_LOGIC_VECTOR (3 downto 0);
signal rd_ex : STD_LOGIC_VECTOR (3 downto 0);
signal imm_ex : STD_LOGIC_VECTOR (15 downto 0);
signal aluCode_ex : STD_LOGIC_VECTOR (3 downto 0);
signal rm_ex : STD_LOGIC;
signal wm_ex : STD_LOGIC;
signal wb_ex : STD_LOGIC;
signal pc_en_ex : STD_LOGIC;
signal imm_en_ex : STD_LOGIC;
signal pc_ex : STD_LOGIC_VECTOR(15 downto 0);
signal data1_ex : STD_LOGIC_VECTOR(15 downto 0);
signal data2_ex : STD_LOGIC_VECTOR(15 downto 0);

signal alu_a_ex : STD_LOGIC_VECTOR(15 downto 0);
signal alu_b_ex : STD_LOGIC_VECTOR(15 downto 0);
signal alu_sign,alu_zero,alu_over,alu_co: std_logic;
signal result_ex : STD_LOGIC_VECTOR(15 downto 0);

signal wb_mem,wm_mem,rm_mem : std_logic;
signal rd_mem : STD_LOGIC_VECTOR(3 downto 0);
signal result_mem,data2_mem,data_out_mem, wbdata_mem : std_logic_vector(15 downto 0);
			  
signal rd_wb : STD_LOGIC_VECTOR(3 downto 0);
signal datain_wb : STD_LOGIC_VECTOR(15 downto 0);
signal wb_wb : STD_LOGIC;

begin

	process(clk)
	begin
		if clk'event and clk = '1' then
			clk_2 <= not clk_2;
		end if;
	end process;
	
	process(clk_2)
	begin
		if clk_2'event and clk_2 = '1' then
			clk_4 <= not clk_4;
		end if;
	end process;
	
	process(clk_4)
	begin
		if clk_4'event and clk_4 = '1' then
			clk_8 <= not clk_8;
		end if;
	end process;
	
	
	
	pc : pc_module port map
	      ( current_pc => pc_if,
           branch_pc => bra_pc,
           branch_en => bra_en,
			  clk => clk_8);
	
--	if_c : IF_ram2 port map
--	(
--		CLK => clk,
--		RST => rst,
--		EN => en_if,
--		pc => pc_if,
--		Ram2Addr => ram2_addr,
--		Ram2Data => ram2_data,
--		instruction => instruction_if,
--		Ram2OE => ram2_oe, 
--		Ram2WE => ram2_we,
--		Ram2EN => ram2_en
--	);
	
	instruction_if <= instruction_test;

	if_id_c : IF_ID port map
         ( pc_in => pc_if,
           instruction_in => instruction_if,
           clk => clk_8,
           instruction_out => instruction_id,
           pc_out => pc_id
	      );

	dec : decoder port map(
			  instruction=>instruction_id,
           rs1=>rs1_id,
           rs2=>rs2_id,
           rd=>rd_id,
           imm=>imm_id,
           immCode=>immCode_id,
           aluCode=>aluCode_id,
           rm=>rm_id,
           wm=>wm_id,
           wb=>wb_id,
           pc_en=>pc_en_id,
			  imm_en =>imm_en_id
			  );
	
	reg : registers port map
	      ( --en => ,
			  clk => clk_4,
           rs1 => rs1_id,
           rs2 => rs2_id,
           rd => rd_wb,
           datain => datain_wb,
           dataOut_1 => dataOut_1_id,
           dataOut_2 => dataOut_2_id);
	
	extend : extender port map
         ( imm => imm_id,
           immCode => immCode_id,
           extension => immExt_id);
			  
	
	id_ex_c : id_ex port map(
		clk=>clk_8,
		wb_in=>wb_id,
		wm_in=>wm_id,
		alu_in=>aluCode_id,
		data1_in=>dataOut_1_id,
		data2_in=>dataOut_2_id,
		imm_in=>immExt_id,
		rd_in=>rd_id,
		rs1_in=>rs1_id,
		rs2_in=>rs2_id,
		rm_in=>rm_id,
		pcen_in=>pc_en_id,
		immen_in=>imm_en_id,
		nextpc_in=>pc_id,
		instruction_in=>instruction_id,
		wb_out=>wb_ex,
		wm_out=>wm_ex,
		alu_out=>aluCode_ex,
		data1_out=>data1_ex,
		data2_out=>data2_ex,
		imm_out=>imm_ex,
		rd_out=>rd_ex,
		rs1_out=>rs1_ex,
		rs2_out=>rs2_ex,
		rm_out=>rm_ex,
		pcen_out=>pc_en_ex,
		immen_out=>imm_en_ex,
		nextpc_out=>pc_ex,
		instruction_out=>instruction_ex
	);
	
	alu_c : alu port map
	  (alucode=>aluCode_ex,
		a=>alu_a_ex,
		b=>alu_b_ex,
		sign=>alu_sign,
		zero=>alu_zero,
		over=>alu_over,
		co=>alu_co,
		y=>result_ex
		);
	process(clk)
	begin
		output_test<=result_ex;
		if (rm_mem = '1' or wm_mem='1') then
			output_test <= data2_mem;
		end if;
	end process;
		

	process(imm_en_ex,data2_ex,clk)
	begin
		alu_b_ex<=data2_ex;
		if imm_en_ex='1' then
			alu_b_ex<=imm_ex;
		end if;
	end process;
	
	process(pc_en_ex,data1_ex,clk)
	begin
		alu_a_ex<=data1_ex;
		if pc_en_ex='1' then
			alu_a_ex<=pc_ex;
		end if;
	end process;
	
	branch : branch_decision port map
         ( newpc_alu => result_ex,
           cond_data2 => data2_ex,
           instruction => instruction_ex,
           branch_en => bra_en,
           branch_pc => bra_pc);
			  
	ex_mem_c : ex_mem port map
	(	clk=>clk_8,
		wb_in=>wb_ex,
		wm_in=>wm_ex,
		rm_in=>rm_ex,
		rd_in=>rd_ex,
		result_in=>result_ex,
		data2_in=>data2_ex,
		wb_out=>wb_mem,
		wm_out=>wm_mem,
		rm_out=>rm_mem,
		rd_out=>rd_mem,
		result_out=>result_mem,
		data2_out=>data2_mem
	);


	mem : MEM_ram1 port map
	(
		CLK => clk,
		RST => rst,
		rm => rm_mem,
		wm => wm_mem,
		addr => result_mem,
		data_in => data2_mem,
		data_out => data_out_mem,
		Ram1Addr => ram1_addr,
		Ram1Data => ram1_data,

		data_ready => data_ready,
		rdn => rdn,
		wrn => wrn,
		tbre => tbre,
		tsre => tsre,
		ram1_en => ram1_en,
		ram1_oe => ram1_oe, 
		ram1_we => ram1_we
	);
	
	process(rm_mem,clk)
	begin
		wbdata_mem <= result_mem;
		if rm_mem = '1' then
			wbdata_mem <= data_out_mem;
		end if;
	end process;
	
	mem_wb_c : MEM_WB port map
   (
		wb_in => wb_mem,
      rd_in => rd_mem,
      data_in => wbdata_mem,
      clk => clk_8,
      data_out => datain_wb,
      wb_out => wb_wb,
      rd_out => rd_wb
	);

	


end Behavioral;

